// 深拷贝和浅拷贝

// 如何把对象复制给另一个对象？

// 一、浅拷贝

// 1. 直接赋值

let obj1 = {
    name: "jayjun",
    age: 18
};

let obj2 = obj1;
console.log(obj1, obj2);

obj1.age = 19;
console.log(obj1, obj2);

// 2. Object.assign()：合并对象

// 语法：Object.assign(target, ...sources)
// 参数target：必需，目标对象，接收源对象属性的对象，也就是修改后的返回值
// 参数sources：可选，源对象，包含将被合并的属性
// 返回值：目标对象

let target = {
    a: 1,
    b: 2
}

let source = {
    b: 3,
    c: 4
}

Object.assign(target, source);
console.log(target);

// 复制对象

// 写法一
let target2 = {};
Object.assign(target2, source);
console.log(target2);

// 写法二
let returnedTarget = Object.assign({}, source);
console.log(returnedTarget);

// 如果对象属性具有多层嵌套，这时使用Object.assign()复制对象会怎么样呢？Object.assign()真的靠谱吗？

let target3 = {
    a: {
        b: 1,
        c: 2
    },
    e: 4,
    f: 5
}

let source3 = {
    a: {
        b: 1
    },
    e: 2,
    f: 3
}

// 此时你会发现，c属性消失了。说明Object.assign不靠谱，Object.assign对于引用类型的复制也是浅拷贝。

Object.assign(target3, source3);
console.log(target3);

// 二、 深拷贝

// 1. 使用 JSON 方法

// JSON.stringify() 将对象转换成JSON字符串，串行化

let user = {
    name: "jayjun",
    age: 18
};

console.log(user);  // {name: 'jayjun', age: 18}

let userJson = JSON.stringify(user);
console.log(userJson);  // '{"name": "jayjun", "age": 18}'

// JSON.parse() 将JSON字符串转换成对象，反串行化

let user2 = JSON.parse(userJson); 
console.log(user2); // {name: 'jayjun', age: 18}

let target4 = {
    a: {
        b: 1,
        c: 2
    },
    e: 4,
    f: 5
}

let source4 = JSON.parse(JSON.stringify(target4));
console.log(source4);

// 但是这种JSON方式存在弊端，会忽略 undefined、Symbol 和函数。

let obj4 = {
    a: 1,
    b: undefined,
    c: function() {},
    d: Symbol(2)
}

let obj5 = JSON.parse(JSON.stringify(obj4));

console.log(obj4, obj5);

// 2、如何手写函数实现一个深拷贝？

// 检测类型
let checkType = data => {
    return Object.prototype.toString.call(data).slice(8, -1);
}

// 递归函数实现深拷贝

let deepClone = target => {
    let result; // 存储拷贝结果
    let targetType = checkType(target); // 调用检测类型函数获取target的类型

    // 判断target的类型是否为引用类型
    if (targetType === "Array") {
        result = []; // 如果target是数组类型，则result赋值为[]
    } else if (targetType === "Object") {
        result = {}; // 如果target是对象类型，则result赋值为{}
    } else {
        return target; // 如果target不是引用类型，则直接返回target
    }

    // 遍历 target
    for(let index in target) {
        let value = target[index]; // 获取遍历的value
        let valueType = checkType(value); // 调用检测类型函数获取value类型
        if (valueType === "Array" || valueType === "Object") {
            result[index] = deepClone(value); // 如果是引用类型，则递归调用，并将结果赋值给result[index]
        } else {
            result[index] = value; // 如果不是引用类型，直接将value赋值给result[index]
        }
    }

    return result; // 返回拷贝结果
}

// 检测
let target5 = {
    a: {
        b: 1,
        c: 2
    },
    e: 4,
    f: 5
}

let result = deepClone(target5);
console.log(result);

let user3 = {
    name: "jayjun",
    age: 18,
    likes: ["coding", "eating"]
};

let user4 = deepClone(user3);
console.log(user3, user4);

user3.likes[0] = "sleeping";
console.log(user3, user4);